using Commons.Utils;
using System;
using System.Collections.Generic;
using System.Reflection;

namespace Commons.Injector
{
	public class ListDefinition : ObjectDefinition
	{
		public List<ListItemDefinition> items;
		public string objectRef;
		public string propertyRef;
		public MethodInfo addMethod;

		public ListDefinition()
		{
			items = new List<ListItemDefinition>();
			singleton = false;
		}

		public static object CreateGeneric(Type generic, Type innerType, params object[] args)
		{
			Type specificType = generic.MakeGenericType(new Type[] { innerType });
			return Activator.CreateInstance(specificType, args);
		}

		private MethodInfo GetAddMethod(object target, Type itemType)
		{
			return target.GetType().GetMethod("Add", new Type[] { itemType });
		}

		private void AddItem(object list, object item)
		{
			if (addMethod != null)
			{
				addMethod.Invoke(list, new object[] { item });
			}
		}

		public void SetListValues(object list, Dictionary<string,object> globalReferences, Dictionary<string,object> localReferences, Type innerType)
		{	
			foreach (ListItemDefinition itemDef in items)
			{
				object value;
				if (itemDef.refId == null)
				{
					value = Convert.ChangeType(itemDef.value, innerType);
				}
				else
				{
					value = localReferences.ContainsKey(itemDef.refId) ? localReferences[itemDef.refId] : globalReferences[itemDef.refId];
				}
				AddItem(list, value);
			}
		}

		public override object Instantiate(Dictionary<string, object> globalReferences, Dictionary<string,object> localReferences)
		{
			Type itemType = ReflectionHelper.GetCustomType(className);
			object list = CreateGeneric(typeof(List<>), itemType, null);
			addMethod = GetAddMethod(list, itemType);
			SetListValues(list, globalReferences, localReferences, itemType);

			return list;
		}
	}
}
